package com.proxy.server.service;


import com.proxy.common.entity.ClientNode;
import com.proxy.common.entity.ProxyRealServer;
import com.proxy.common.protocol.CommonConstant;
import com.proxy.server.dao.ClientDao;
import com.proxy.server.handler.HttpChannelHandler;
import com.proxy.server.handler.TCPChannelHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
 * 代理客户端 管理
 */
public class ClientService {

    private static Logger logger = LoggerFactory.getLogger(ClientService.class);

    private static ClientDao clientDao =new ClientDao();

    public void add(String clientKey, ClientNode node){

        //1.添加客户端
        clientDao.add(clientKey,node);

        if(node.getStatus()!= CommonConstant.ClientStatus.ONLINE){
            return;
        }

        //2.开始为客户端绑定服务端口

        //绑定客户端服务端口
        NioEventLoopGroup serverWorkerGroup;
        NioEventLoopGroup serverBossGroup;

        Map<Integer, ProxyRealServer> keyToNode = node.getServerPort2RealServer();
        for (Map.Entry<Integer, ProxyRealServer> temp : keyToNode.entrySet()) {

            ProxyRealServer proxyRealServer  = temp.getValue();

            if (ServerBeanManager.getLocalPortBindService().get(temp.getKey())!=null && ServerBeanManager.getLocalPortBindService().get(temp.getKey()).getStatus()==CommonConstant.ProxyStatus.ONLINE){
                logger.error("服务端口 {} 已经被绑定了",temp.getKey());
                continue;
            }

            serverBossGroup = new NioEventLoopGroup();
            serverWorkerGroup = new NioEventLoopGroup();
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(serverBossGroup, serverWorkerGroup).channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch) throws Exception {

                                ch.pipeline().addLast(SharableHandlerManager.getTrafficLimitHandler());
                                ch.pipeline().addLast(SharableHandlerManager.getTrafficCollectionHandler());
                                ch.pipeline().addLast(new TCPChannelHandler());
                                //HttpRequestDecoder http请求消息解码器
                                ch.pipeline().addLast("httpDecoder",new HttpRequestDecoder());
                                //解析 HTTP POST 请求
                                ch.pipeline().addLast("httpObject",new HttpObjectAggregator(2*1024*1024));
                                ch.pipeline().addLast(new HttpChannelHandler());
                            }
                        });
            try {
                //绑定服务端口,会更新代理状态
                ServerBeanManager.getLocalPortBindService().bind(temp.getKey(), bootstrap,proxyRealServer);
//                ServerBeanManager.getLocalPortBindService().get(temp.getKey()).setStatus(CommonConstant.ProxyStatus.ONLINE);
            } catch (Exception e) {
                logger.error("服务端口 {} 绑定失败:"+e.getMessage(),temp.getKey());
            }
        }

    }

    public String getClientKey(Channel channel){
        return clientDao.getClientKey(channel);
    }
    public void delete(String clientKey){
        if (clientKey!=null)
            clientDao.remove(clientKey);
    }
    public void setNodeStatus(String clientKey,Integer status){
        clientDao.setNodeStatus(clientKey,status);
    }
    public ClientNode get(String clientKey){
        if (clientKey!=null)
            return  clientDao.get(clientKey);
        return null;
    }
    public void setNodeChannle(String clientKey,Channel channel){
        clientDao.setNodeChannle(clientKey,channel);
    }

    public Map<String, ClientNode> getAllNode(){
        return clientDao.getAll();
    }

}
